#include "PCResourceUI.h"
#include "lvgl/lvgl.h"
#include "themes/PCResource_theme_default.h"
#include "themes/PCResource_theme_light.h"
#include "themes/PCResource_theme_sky.h"
#include "themes/PCResource_theme_miku.h"
#include "themes/PCResource_theme_bilibili.h"

#define MAX_THEME 10 // 最大支持主题数

LV_IMG_DECLARE(butterfly)

static void addTheme(const char *name, gui_theme_operations *opts);
static void changeTheme(int tag);
static void showNextTheme(void);
static void showPrevTheme(void);

static void drag_event_handler(lv_event_t *e);
static void screen_gusture_event_cb(lv_event_t *e);

// UI回调函数集合
static PCResourceUI::Operations uiOpts;

// 界面容器
static lv_obj_t *cont;

// 退出按钮
static lv_obj_t *exitBtn = nullptr;

// 主题操作函数集合
static gui_theme_operations themeOpts[MAX_THEME];

// 当前主题索引
static int activeThemeIndex;

// 已添加的主题数目
static int totalTheme = 0;

/**
 *@brief 初始化基本UI
 *@param opts 回调函数集合
 */
void PCResourceUI::create(Operations &opts)
{
  uiOpts = opts;
  uiOpts.showNextTheme = showNextTheme;

  // 创建容器
  cont = lv_obj_create(lv_scr_act());
  lv_obj_set_size(cont, 1024, 600);
  lv_obj_clear_flag(cont, LV_OBJ_FLAG_SCROLLABLE);           // 禁止对象滚动
  lv_obj_set_style_border_width(cont, 0, LV_STATE_DEFAULT);  // 边框宽度0
  lv_obj_set_style_pad_all(cont, 0, LV_STATE_DEFAULT);       // 四周填充宽度0
  lv_obj_set_style_outline_width(cont, 0, LV_STATE_DEFAULT); // 外部线条宽度0
  lv_obj_center(cont);

  // 为屏幕创建手势事件回调函数
  lv_obj_add_flag(lv_scr_act(), LV_OBJ_FLAG_CLICKABLE);
  lv_obj_clear_flag(lv_scr_act(), LV_OBJ_FLAG_SCROLLABLE);                               // 禁止滚动
  lv_obj_add_event_cb(lv_scr_act(), screen_gusture_event_cb, LV_EVENT_GESTURE, nullptr); // 屏幕手势事件，用于切换主题

  // 创建退出按钮
  exitBtn = lv_obj_create(lv_layer_sys());
  lv_obj_set_size(exitBtn, 70, 70);
  lv_obj_set_pos(exitBtn, 935, 267);
  lv_obj_clear_flag(exitBtn, LV_OBJ_FLAG_SCROLLABLE); // 禁止滚动
  lv_obj_set_style_radius(exitBtn, 35, LV_STATE_DEFAULT);
  lv_obj_set_style_bg_color(exitBtn, lv_color_hex(0xffffff), LV_STATE_DEFAULT);
  lv_obj_set_style_border_opa(exitBtn, LV_OPA_TRANSP, LV_STATE_DEFAULT); // A边框透明
  lv_obj_set_style_bg_opa(exitBtn, LV_OPA_50, LV_STATE_DEFAULT);
  lv_obj_set_style_bg_opa(exitBtn, LV_OPA_90, LV_STATE_PRESSED);

  lv_obj_t *img = lv_img_create(exitBtn);
  lv_img_set_src(img, &butterfly);
  lv_obj_align(img, LV_ALIGN_CENTER, 0, 0);
  lv_obj_add_flag(img, LV_OBJ_FLAG_EVENT_BUBBLE);

  lv_obj_add_event_cb(exitBtn, drag_event_handler, LV_EVENT_PRESSING, nullptr);
  if (uiOpts.exitCb != nullptr)
    lv_obj_add_event_cb(
        exitBtn,
        [](lv_event_t *e)
        {
          uiOpts.exitCb();
        },
        LV_EVENT_SHORT_CLICKED, nullptr);

  // 添加主题
  addTheme("default", &default_theme);
  addTheme("light", &light_theme);
  addTheme("sky", &sky_theme);
  addTheme("miku", &miku_theme);
  addTheme("bilibili", &bilibili_theme);

  themeOpts[0].init(cont); // 初始化第一个主题
  activeThemeIndex = 0;
}

/**
 *@brief 更新UI显示数据
 *@param info PC硬件资源数据
 */
void PCResourceUI::update(PCResInfo &info)
{
  if (themeOpts[activeThemeIndex].update != nullptr)
    themeOpts[activeThemeIndex].update(&info);
}

/**
 *@brief 释放UI资源
 */
void PCResourceUI::release(void)
{
  if (themeOpts[activeThemeIndex].release != nullptr)
    themeOpts[activeThemeIndex].release();

  lv_obj_del(cont);
  lv_obj_del(exitBtn);
}

/**
 *@brief 添加主题
 *@param name 主题名称
 *@param opts 主题操作函数集
 */
static void addTheme(const char *name, gui_theme_operations *opts)
{
  if (opts == nullptr && totalTheme >= MAX_THEME)
    return;

  memcpy(&themeOpts[totalTheme], opts, sizeof(gui_theme_operations)); // 设置主题操作函数集

  totalTheme++;
}
/**
 *@brief 切换UI主题
 *@param tag 切换的主题索引
 */
static void changeTheme(int tag)
{
  if (tag < 0 || tag >= totalTheme)
    return;

  if (themeOpts[activeThemeIndex].release != nullptr)
    themeOpts[activeThemeIndex].release(); // 释放上一个主题的资源

  if (themeOpts[tag].init != nullptr)
    themeOpts[tag].init(cont); // 初始化新的主题

  activeThemeIndex = tag; // 设置新的活跃主题
}

/**
 *@brief 切换到下一个主题
 */
static void showNextTheme(void)
{
  int tag = activeThemeIndex;

  tag = tag < totalTheme - 1 ? tag + 1 : 0;

  changeTheme(tag);
}

/**
 *@brief 切换到上一个主题
 */
static void showPrevTheme(void)
{
  int tag = activeThemeIndex;

  tag = tag > 0 ? tag - 1 : totalTheme - 1;

  changeTheme(tag);
}

/**
 *@brief 长按拖动控件事件函数
 */
static void drag_event_handler(lv_event_t *e)
{
  lv_obj_t *obj = lv_event_get_target(e);

  lv_indev_t *indev = lv_indev_get_act();
  if (indev == nullptr)
    return;

  lv_point_t vect;
  lv_indev_get_vect(indev, &vect);

  lv_coord_t x = lv_obj_get_x(obj) + vect.x;
  lv_coord_t y = lv_obj_get_y(obj) + vect.y;
  lv_obj_set_pos(obj, x, y);
}

/**
 * @brief 屏幕手势滑动事件(用于切换主题)
 */
static void screen_gusture_event_cb(lv_event_t *e)
{
  lv_indev_wait_release(lv_indev_get_act());

  lv_dir_t dir = lv_indev_get_gesture_dir(lv_indev_get_act());

  switch (dir)
  {
  case LV_DIR_RIGHT:
    showPrevTheme();
    break;
  case LV_DIR_LEFT:
    showNextTheme();
    break;
  default:
    return;
  }
}

/**
 *@brief 图表自动刻度设置
 *@param chart 图表
 *@param series 数据系列
 *@param min 刻度最小值设定
 *@param max 刻度最大值的下限
 *@note 此函数仅供主题使用
 */
void chart_auto_scale(lv_obj_t *chart, lv_chart_series_t *series, int min, int max)
{
  int max_value = max;

  int total_point = lv_chart_get_point_count(chart);       // 获取总点数
  lv_coord_t *array = lv_chart_get_y_array(chart, series); // 获取点数组

  for (int j = 0; j < total_point; j++)
    max_value = max_value < array[j] ? array[j] : max_value; // 计算当前所有点中最大值

  lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, min, max_value);
}

/**
 *@brief 图表 数据下方区域填充绘制回调
 *@note 此函数仅供主题使用
 */
void chart_draw_evnet_cb(lv_event_t *e)
{
  lv_obj_t *obj = lv_event_get_target(e);

  /*Add the faded area before the lines are drawn*/
  lv_obj_draw_part_dsc_t *dsc = lv_event_get_draw_part_dsc(e);
  if (dsc->part == LV_PART_ITEMS)
  {
    if (!dsc->p1 || !dsc->p2)
      return;

    /*Add a line mask that keeps the area below the line*/
    lv_draw_mask_line_param_t line_mask_param;
    lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->p2->x, dsc->p2->y, LV_DRAW_MASK_LINE_SIDE_BOTTOM);
    int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, nullptr);

    /*Add a fade effect: transparent bottom covering top*/
    lv_coord_t h = lv_obj_get_height(obj);
    lv_draw_mask_fade_param_t fade_mask_param;
    lv_draw_mask_fade_init(&fade_mask_param, &obj->coords, LV_OPA_COVER, obj->coords.y1 + h / 8, LV_OPA_TRANSP, obj->coords.y2);
    int16_t fade_mask_id = lv_draw_mask_add(&fade_mask_param, nullptr);

    /*Draw a rectangle that will be affected by the mask*/
    lv_draw_rect_dsc_t draw_rect_dsc;
    lv_draw_rect_dsc_init(&draw_rect_dsc);
    draw_rect_dsc.bg_opa = LV_OPA_80;
    draw_rect_dsc.bg_color = dsc->line_dsc->color;

    lv_area_t a;
    a.x1 = dsc->p1->x;
    a.x2 = dsc->p2->x - 1;
    a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y);
    a.y2 = obj->coords.y2;
    lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a);

    /*Remove the masks*/
    lv_draw_mask_free_param(&line_mask_param);
    lv_draw_mask_free_param(&fade_mask_param);
    lv_draw_mask_remove_id(line_mask_id);
    lv_draw_mask_remove_id(fade_mask_id);
  }
}
